﻿using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Fetion.Util
{
    //注意AES是一个对称加密算法,用来加密和解密数据的密码和salt值必须相同
    public class AESEncryption
    {
        public static string Encrypt2(string input, string password)
        {
            var byteArray = Encoding.UTF8.GetBytes(input);
            var key = MD5Core.GetHash(Encoding.UTF8.GetBytes(password));//Encoding.UTF8.GetBytes(password);
            var encryptioncipher = CipherUtilities.GetCipher("AES/ECB/PKCS7");//PKCS5PADDING，PKCS7
            encryptioncipher.Init(true, new KeyParameter(key));
            //string algo = encryptioncipher.AlgorithmName; 
            int blocksize = encryptioncipher.GetBlockSize();
            byte[] bytes = encryptioncipher.ProcessBytes(byteArray);
            byte[] final = encryptioncipher.DoFinal();
            string resultBytes = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
            MemoryStream encryptedstream = new MemoryStream(bytes.Length + final.Length);
            encryptedstream.Write(bytes, 0, bytes.Length);
            encryptedstream.Write(final, 0, final.Length);
            encryptedstream.Flush(); byte[] encryptedData = new byte[encryptedstream.Length];
            encryptedstream.Position = 0; encryptedstream.Read(encryptedData, 0, encryptedData.Length);
            //Convert to hex string 
            string result = MiMaHelper.ToHexString(encryptedData).ToLower();
            //string jiestr = Decrypt2(encryptedData, password);
            return result;
        }
        public static string Decrypt2(byte[] encryptedhexstring, string password)
        {
            byte[] encryptedData = encryptedhexstring;// Encoding.UTF8.GetBytes(encryptedhexstring); //HexHelper.GetBytes(encryptedhexstring);
            var key = MD5Core.GetHash(Encoding.UTF8.GetBytes(password));//Encoding.UTF8.GetBytes(password);
            // AES algorthim with ECB cipher &amp; PKCS5 padding... 
            var cipher = CipherUtilities.GetCipher("AES/ECB/PKCS7");
            // Initialise the cipher... 
            cipher.Init(false, new KeyParameter(key));
            // Decrypt the data and write the 'final' byte stream... 
            var decryptionbytes = cipher.ProcessBytes(encryptedData);
            var decryptedfinal = cipher.DoFinal();
            // Write the decrypt bytes &amp; final to memory... 
            var decryptedstream = new MemoryStream(decryptionbytes.Length);
            decryptedstream.Write(decryptionbytes, 0, decryptionbytes.Length);
            decryptedstream.Write(decryptedfinal, 0, decryptedfinal.Length);
            decryptedstream.Flush();
            var decryptedData = new byte[decryptedstream.Length];
            decryptedstream.Position = 0;
            decryptedstream.Read(decryptedData, 0, (int)decryptedstream.Length);
            // Convert the decrypted data to a string value... 
            var resultdecrypted = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
            return resultdecrypted;
        }
        public static string Decrypt2(string encryptedhexstring, string password)
        {
            byte[] encryptedData =Encoding.UTF8.GetBytes(encryptedhexstring); //HexHelper.GetBytes(encryptedhexstring);
            var key = MD5Core.GetHash(Encoding.UTF8.GetBytes(password));//Encoding.UTF8.GetBytes(password);
            // AES algorthim with ECB cipher &amp; PKCS5 padding... 
            var cipher = CipherUtilities.GetCipher("AES/ECB/PKCS7");
            // Initialise the cipher... 
            cipher.Init(false, new KeyParameter(key));
            // Decrypt the data and write the 'final' byte stream... 
            var decryptionbytes = cipher.ProcessBytes(encryptedData);
            var decryptedfinal = cipher.DoFinal();
            // Write the decrypt bytes &amp; final to memory... 
            var decryptedstream = new MemoryStream(decryptionbytes.Length);
            decryptedstream.Write(decryptionbytes, 0, decryptionbytes.Length);
            decryptedstream.Write(decryptedfinal, 0, decryptedfinal.Length);
            decryptedstream.Flush();
            var decryptedData = new byte[decryptedstream.Length];
            decryptedstream.Position = 0;
            decryptedstream.Read(decryptedData, 0, (int)decryptedstream.Length);
            // Convert the decrypted data to a string value... 
            var resultdecrypted = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
            return resultdecrypted;
        }
        byte[] byteIV = new byte[] { 0, 0x39, (byte)0x9f, 0x3d, 0x12, 0x5d, (byte)0xb5, 0x53, 0x0a, (byte)0xb5, (byte)0xe0, 0x00, (byte)0xd6, (byte)0xb0, (byte)0xf4, 0x5a };
        /// <summary>
        /// 加密数据
        /// </summary>
        /// <param name="dataToEncrypt">要加密的字符串</param>
        /// <param name="password">密码</param>
        /// <param name="salt">salt值</param>
        /// <returns></returns>
        public static string Encrypt(string dataToEncrypt, string password, string salt)
        {
            AesManaged aes = null;
            MemoryStream stream = null;
            CryptoStream cryptoStream = null;
            try
            {
                Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
                aes = new AesManaged();
                //aes.GenerateIV();
                aes.Key = rfc2898.GetBytes(aes.KeySize / 8);//设置用于对称算法的密钥
                aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);//设置用于对称算法的初始化向量(IV)
                stream = new MemoryStream();
                //使用当前的密钥和初始化向量(IV)创建对称加密器对象
                cryptoStream = new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Write);
                byte[] data = Encoding.UTF8.GetBytes(dataToEncrypt);
                cryptoStream.Write(data, 0, data.Length);
                cryptoStream.FlushFinalBlock();
                return Convert.ToBase64String(stream.ToArray());
            }
            finally
            {
                //关闭当前流并释放与当前流相关的任何资源
                if (cryptoStream != null)
                {
                    cryptoStream.Close();
                }
                if (stream != null)
                {
                    stream.Close();
                }
                if (aes != null)
                {
                    //释放资源
                    aes.Clear();
                }
            }
        }


        /// <summary>
        ///  解密数据
        /// </summary>
        /// <param name="dataToDecrypt">需要解密的数据</param>
        /// <param name="password">密码</param>
        /// <param name="salt">salt值</param>
        /// <returns></returns>
        public static string Decrypt(string dataToDecrypt, string password, string salt)
        {
            AesManaged aes = null;
            MemoryStream stream = null;
            CryptoStream cryptoStream = null;
            try
            {
                Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
                aes = new AesManaged();
                aes.Key = rfc2898.GetBytes(aes.KeySize / 8);//设置用于对称算法的密钥
                aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);//设置用于对称算法的初始化向量(IV)
                stream = new MemoryStream();
                //使用当前的密钥和初始化向量(IV)创建对称解密器对象
                cryptoStream = new CryptoStream(stream, aes.CreateDecryptor(), CryptoStreamMode.Write);
                byte[] data = Encoding.UTF8.GetBytes(dataToDecrypt);
                cryptoStream.Write(data, 0, data.Length);
                cryptoStream.FlushFinalBlock();

                byte[] decryptBytes = stream.ToArray();
                return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
            }
            finally
            {
                //关闭当前流并释放与当前流相关的任何资源
                if (cryptoStream != null)
                {
                    cryptoStream.Close();
                }
                if (stream != null)
                {
                    stream.Close();
                }
                if (aes != null)
                {
                    //释放资源
                    aes.Clear();
                }
            }
        }
    }
}
